/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import fileio from '@ohos.fileio'
import errorCode from '../../node/error-code'
import { fromCallback } from '../../universalify'
import pathEx from '../path-exists'

function readlinkSync(path) {
    return path;
}

function readlink(path, cb?) {
    if (cb) {
        cb(undefined, path)
    } else {
        return new Promise((resolve) => {
            resolve(readlinkSync(path))
        })
    }
}

function readdir(path, cb) {
    fileio.access(path).then(() => {
        fileio.stat(path).then((stat) => {
            if (stat.isDirectory()) {
                fileio.opendir(path).then((dir) => {
                    let list = [];
                    while (true) {
                        try {
                            let dirent = dir.readSync();
                            list.push(dirent.name)
                        } catch (err) {
                            break
                        }
                    }
                    if (cb) {
                        cb(undefined, list)
                    }
                }).catch((err) => {
                    cb(err);
                })
            } else {
                let err = new Error();
                err.message = 'Not a directory'
                cb(err);
            }
        }).catch((err) => {
            cb(err);
        })
    })
}

function readdirSync(path) {
    fileio.accessSync(path);
    let stat = fileio.statSync(path);
    if (stat.isDirectory()) {
        let dir = fileio.opendirSync(path);
        let list = [];
        while (true) {
            try {
                let dirent = dir.readSync();
                list.push(dirent.name)
            } catch (err) {
                break
            }
        }
        return list;
    } else {
        let err = new Error();
        err.message = errorCode.errormessage.ENOTDIR
        throw err
    }
}

function existsSync(path) {
    try {
        fileio.accessSync(path);
        return true;
    } catch (err) {
        return false;
    }
}

function writeFile(file, data, options?, callback?) {
    if (typeof options === 'function') {
        callback = options
        options = {
            encoding: 'utf-8'
        }
    }
    if (typeof file === 'number') {
        fileio.write(file, data, options, callback)
    } else {
        let pathex = pathEx.pathExistsSync(file)
        if (pathex) {
            let fdw = fileio.openSync(file, 0o1000);
        }
        fileio.open(file, 0o2 | 0o100, 0o666).then((fd) => {
            fileio.write(fd, data, options, callback)
        }).catch(err => {
            callback(err);
        })
    }
}

function writeFileSync(file, data, options?) {
    if (typeof file === 'number') {
        return fileio.writeSync(file, data, options)
    }
    let pathex = pathEx.pathExistsSync(file)
    if (pathex) {
        let fdw = fileio.openSync(file, 0o1000);
    }
    let fd = fileio.openSync(file, 0o2 | 0o100, 0o666);
    return fileio.writeSync(fd, data, options);
}

function statSync(path) {
    let stat = fileio.statSync(path);
    return getStat(stat);
}

function lstatSync(path) {
    let stat = fileio.statSync(path);
    return getStat(stat);
}

function stat(path, callback) {
    fileio.stat(path, (err, stat) => {
        callback(err, getStat(stat));
    })
}

function lstat(path, callback) {
    fileio.stat(path, (err, stat) => {
        callback(err, getStat(stat));
    })
}

function getStat(stat) {
    if (stat) {
        let blockDevice = stat.isBlockDevice();
        let characterDevice = stat.isCharacterDevice();
        let directory = stat.isDirectory();
        let FIFO = stat.isFIFO();
        let file = stat.isFile();
        let socket = stat.isSocket();
        let symbolicLink = stat.isSymbolicLink();
        let result = {
            dev: stat.dev,
            ino: stat.ino,
            mode: stat.mode,
            nlink: stat.nlink,
            uid: stat.uid,
            gid: stat.gid,
            rdev: stat.rdev,
            size: stat.size,
            blocks: stat.blocks,
            atime: stat.atime,
            ntime: stat.ctime,
            isBlockDevice: function () {
                return blockDevice;
            },
            isCharacterDevice: function () {
                return characterDevice;
            },
            isDirectory: function () {
                return directory;
            },
            isFIFO: function () {
                return FIFO;
            },
            isFile: function () {
                return file;
            },
            isSocket: function () {
                return socket;
            },
            isSymbolicLink: function () {
                return symbolicLink;
            }
        }
        return result
    }
}

export default {
    access: fileio.access,
    chmod: fileio.chmod,
    chmodSync: fileio.chmodSync,
    copyFile: fileio.copyFile,
    copyFileSync: fileio.copyFileSync,
    existsSync,
    lstat: fromCallback(lstat),
    lstatSync,
    mkdir: fileio.mkdir,
    mkdirSync: fileio.mkdirSync,
    readdir: fromCallback(readdir),
    readdirSync,
    readlink,
    readlinkSync,
    readText: fileio.readText,
    readTextSync: fileio.readTextSync,
    rename: fileio.rename,
    renameSync: fileio.renameSync,
    rmdir: fileio.rmdir,
    rmdirSync: fileio.rmdirSync,
    stat: fromCallback(stat),
    statSync,
    symlink: fileio.symlink,
    symlinkSync: fileio.symlinkSync,
    unlink: fileio.unlink,
    unlinkSync: fileio.unlinkSync,
    writeFile: fromCallback(writeFile),
    writeFileSync
}